/*
 * Licensed to the Apache Software Foundation (ASF) under one or more
 * contributor license agreements.  See the NOTICE file distributed with
 * this work for additional information regarding copyright ownership.
 * The ASF licenses this file to You under the Apache License, Version 2.0
 * (the "License"); you may not use this file except in compliance with
 * the License.  You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package org.apache.dubbo.config.spring.context.annotation;

import org.apache.dubbo.config.AbstractConfig;

import org.springframework.beans.factory.support.BeanDefinitionRegistry;
import org.springframework.context.annotation.ImportBeanDefinitionRegistrar;
import org.springframework.core.Ordered;
import org.springframework.core.annotation.AnnotationAttributes;
import org.springframework.core.type.AnnotationMetadata;

import static com.alibaba.spring.util.AnnotatedBeanDefinitionRegistryUtils.registerBeans;
import static org.apache.dubbo.config.spring.util.DubboBeanUtils.registerCommonBeans;

/**
 * Dubbo {@link AbstractConfig Config} {@link ImportBeanDefinitionRegistrar register}, which order can be configured
 *
 * @see EnableDubboConfig
 * @see DubboConfigConfiguration
 * @see Ordered
 * @since 2.5.8
 */

/**
 * 这是dubbo通过spring的@Import注解的特性导入的一个bean，这个bean是一个ImportBeanDefinitionRegistrar，是@Import的一个特性，
 * 这个特性是很多开源框架整合spring常用的一种切入点，这个类的处理是由spring来处理的，也就是说dubbo编写的这个类，然后通过spring的@Import导入，而
 * 真正的处理是spring来处理的，也就是duubo的实现逻辑交给了spring来处理，那么这个bean主要处理了那些事情，在spring中只要看到实现了ImportBeanDefinitionRegistrar
 * 接口的都要清楚的明白一件事儿就是要通过这个bean来导入一些bean，也就是注册一些bean
 * 这个bean做的事情其实很简单，就是我们在dubbo的注解也好，配置文件application.properties中配置的dubbo的配置也好，每一种配置在dubbo中
 * 都是一个配置类，这些配置来就是封装了配置信息，比如dubbo.application.name，那么dubbo.application就对应到了dubbo中的一个类
 * ApplicationConfig，还有很多的配置对应的配置类，所以dubbo导入的这个bean的意图很简单
 * 1.读取配置文件中配置的属性，对应dubbo中的配置类，将配置中的属性值读取封装到每一个配置类对象比如ApplicationConfig中；
 * 2.然后生成一个bean放入spring容器中，交给spring来管理。
 * 3.spring在启动过程中会将这些配置信息读取存入一个bean叫environment这个bean对象，dubbo读取配置生成配置对象就从这个bean对象中读取
 * 然后封装成对应的配置bean，放入spring容器中。
 * 在dubbo与springboot的整合过程中，dubbo利用了spring的spi机制，也就是自动装配实现的注册，而不是下面的这个bean，自动装配类
 * org.apache.dubbo.spring.boot.autoconfigure.DubboAutoConfiguration
 *
 *
 */
public class DubboConfigConfigurationRegistrar implements ImportBeanDefinitionRegistrar {

    @Override
    public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) {

        AnnotationAttributes attributes = AnnotationAttributes.fromMap(
                importingClassMetadata.getAnnotationAttributes(EnableDubboConfig.class.getName()));

        /**
         * 这个属性在注解EnableDubboConfig中默认就是true，什么意思呢？就是说在dubbo中有很多的配置是可以使用复数的
         * 就比如说协议dubbo.protocol.name=dubbo，这个配置是一个单数，也就是说应用的通讯协议是dubbo，没有其他的协议，
         * 但是也可以设置多种协议，根据不同的接口使用不同的协议，如果配置了多种协议，那么针对每个service，如果没有配置使用的协议，那么
         * 每个service都会生成多个协议，这个在之前的应用中已经演示过了，比如多种协议：
         * dubbo.protocols.p1.id=dubbo-p1
         * dubbo.protocols.p1.name=dubbo
         * dubbo.protocols.p1.port=30881
         * dubbo.protocols.p1.host=0.0.0.0
         *
         * dubbo.protocols.p2.id=dubbo-p2
         * dubbo.protocols.p2.name=rest
         * dubbo.protocols.p2.port=30882
         * dubbo.protocols.p2.host=0.0.0.0
         * 所以这里需要处理单个的配置，也要处理复数的配置，所以multiple这个配置就是表示是否要处理复数的配置
         */
        boolean multiple = attributes.getBoolean("multiple");

        // Single Config Bindings
        //先处理单数的配置，比如dubbo.application.name,单数和复用使用的配置类不同，一个是Sigle，一个是Multiple
        registerBeans(registry, DubboConfigConfiguration.Single.class);

        if (multiple) { // Since 2.6.6 https://github.com/apache/dubbo/issues/3193
            registerBeans(registry, DubboConfigConfiguration.Multiple.class);
        }

        // Since 2.7.6
        registerCommonBeans(registry);
    }
}
